use crossterm::{
    event::{self, Event, KeyCode},
    terminal::{self},
};
use std::io::{self, BufRead};
use std::path::Path;
use std::process::Command;
use std::thread;
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
use std::{fs::File, vec};

mod teromino;

use teromino::*;

const WIN_POS_X: i32 = 0;
const WIN_POS_Y: i32 = 0;

#[derive(Clone, PartialEq, Eq)]
enum GmAction {
    QUIT,
    UP,
    DOWN,
    LEFT,
    RIGHT,
    MENU,
    HELP,
    UNKNOW,
}

struct FPSCounter {
    last_frame: Instant,
    frame_durations: Vec<Duration>,
}

impl FPSCounter {
    // 创建一个新的FPSCounter对象
    pub fn new() -> Self {
        FPSCounter {
            last_frame: Instant::now(),
            frame_durations: Vec::new(),
        }
    }

    // 调用这个函数表示一帧已经被渲染。
    pub fn tick(&mut self) {
        let now = Instant::now();
        let frame_duration = now - self.last_frame;

        self.frame_durations.push(frame_duration);
        // 移除超过1秒前的帧时长记录
        while self.total_duration() > Duration::from_secs(1) {
            self.frame_durations.remove(0);
        }

        self.last_frame = now;
    }

    // 获取当前的FPS。
    pub fn get_fps(&self) -> usize {
        // 不能除以零，所以需要检查长度
        if self.frame_durations.is_empty() {
            return 0;
        }
        // 由于我们保持frame_durations总和最多为1秒，所以可以直接使用其长度
        self.frame_durations.len()
    }

    // 计算frame_durations中所有持续时间的总和。
    fn total_duration(&self) -> Duration {
        self.frame_durations.iter().sum()
    }
}

#[derive(Clone, Copy, PartialEq, Eq)]
enum BlockStatus {
    NONE,
    ACTIVE,
    FIX,
    CLEAR,
}
#[derive(Clone, PartialEq, Eq)]
struct Block {
    color: Color,
    status: BlockStatus,
}

#[derive(Clone)]
struct TetrisGard {
    grid: Vec<Vec<Block>>,
    x: i32,
    y: i32,
    rows: u32,
    cols: u32,
    active_teromino: Teromino,
    hold_teromino: Teromino,
    next_teromino_list: Vec<Teromino>,
    score: i32,
    lines: i32,
    level: i32,
    speed: i32,
    offset: i32,
}

impl TetrisGard {
    // 构造函数，创建一个给定大小的二维网格并初始化所有值为零
    fn new(pos_x: u32, pos_y: u32, height: usize, width: usize) -> Self {
        let grid = vec![
            vec![
                Block {
                    color: Color::NONE,
                    status: BlockStatus::NONE
                };
                width
            ];
            height
        ];
        let x = WIN_POS_X + pos_x as i32;
        let y = WIN_POS_Y + pos_y as i32;
        let rows = height as u32;
        let cols = width as u32;
        let active_teromino = Teromino::new_rand(0, (cols / 2) as i32);
        let hold_teromino = Teromino::new_rand(0, (cols / 2) as i32);
        let mut next_teromino = Vec::with_capacity(5);
        for _ in 0..5 {
            next_teromino.push(Teromino::new_rand(0, (cols / 2) as i32));
        }
        let score = 0;
        let lines = 0;
        let level = 0;
        let speed = 1;
        let offset = 0;
        TetrisGard {
            grid,
            x,
            y,
            rows,
            cols,
            active_teromino,
            hold_teromino,
            next_teromino_list: next_teromino,
            score,
            lines,
            level,
            speed,
            offset,
        }
    }

    fn reset(&mut self) {
        for row in self.grid.iter_mut() {
            for elem in row.iter_mut() {
                elem.color = Color::NONE;
                elem.status = BlockStatus::NONE;
            }
        }
    }

    fn speed(&self) -> i32 {
        self.speed
    }

    fn new_block(&mut self) {
        self.speed = 1;
        self.active_teromino = self.hold_teromino.clone();
        self.hold_teromino = self.next_teromino_list.remove(0);
        self.next_teromino_list
            .push(Teromino::new_rand(0, (16 / 2) as i32));
    }

    fn update(&mut self, action: GmAction) {
        match action {
            GmAction::UP => {
                // 先进行一次旋转, 如果选择后超出边界, 还原形状
                self.active_teromino.rotate();
                if (self.active_teromino.bound_left() < 1)
                    || (self.active_teromino.bound_right() + self.active_teromino.y
                        >= (self.cols - 1) as i32)
                {
                    self.active_teromino.rotate();
                    self.active_teromino.rotate();
                    self.active_teromino.rotate();
                }
            }
            GmAction::LEFT => {
                // 检查是否可以向左侧移动
                if self.active_teromino.bound_left() >= 1 {
                    self.active_teromino.y -= 1;
                }
            }
            GmAction::RIGHT => {
                // 检查是否可以向右侧移动
                if self.active_teromino.bound_right() + self.active_teromino.y
                    < (self.cols - 1) as i32
                {
                    self.active_teromino.y += 1;
                }
            }
            GmAction::DOWN => {
                self.speed = 15;
            }
            _ => {}
        }

        // 清空行
        let mut clear_lines = 0;
        for i in 0..self.grid.len() {
            let row = self.grid.len() - i - 1;
            let mut line_all_fixed = true;
            for col in 0..self.grid[row].len() {
                if BlockStatus::FIX != self.grid[row][col].status {
                    line_all_fixed = false;
                }
            }
            if line_all_fixed && row > 0 {
                for j in 0..row {
                    self.grid[row - j] = self.grid[row - j - 1].clone();
                }
                clear_lines += 1;
            }
        }

        if clear_lines > 0 {
            self.lines += clear_lines;
            self.score += clear_lines * clear_lines * 10;
        }

        // 碰撞检查
        let (collision, ct) = self.collision_check();
        self.offset = ct;
        if collision && ct == 1 {
            // 发生碰撞, 移动块被固定
            let ter = &self.active_teromino.shape;
            for row in 0..ter.len() {
                for col in 0..ter[row].len() {
                    if 1 == ter[row][col] {
                        let r = self.active_teromino.x + row as i32;
                        let c = self.active_teromino.y + col as i32;
                        let block = &mut self.grid[r as usize][c as usize];
                        block.status = BlockStatus::FIX;
                        block.color = self.active_teromino.color;
                    }
                }
            }
            // 整行都已经被填充, 准备被删除
            for row in 0..self.grid.len() {
                let mut line_all_fixed = true;
                for col in 0..self.grid[row].len() {
                    if BlockStatus::FIX != self.grid[row][col].status {
                        line_all_fixed = false;
                    }
                }
                if line_all_fixed {
                    for col in 0..self.grid[row].len() {
                        self.grid[row][col].color = Color::WHITE;
                    }
                }
            }
            self.new_block();
        } else {
            self.active_teromino.x += 1;
        }
    }

    fn collision_check(&self) -> (bool, i32) {
        let mut collision = false;
        let mut ct = 1;
        {
            while ct < self.rows as i32 {
                let ter = &self.active_teromino.shape;
                for row in 0..ter.len() {
                    for col in 0..ter[row].len() {
                        if 1 == ter[row][col] {
                            // 当前 teromino 的下一行是最后一行或者固定块, 则发生碰撞
                            let r = self.active_teromino.x + ct + row as i32;
                            let c = self.active_teromino.y + col as i32;
                            // 边界检查
                            if r < 0 || r >= (self.rows as i32) {
                                collision = true;
                                break;
                            }
                            if c < 0 || c >= (self.cols as i32) {
                                collision = true;
                                break;
                            }
                            if self.grid[r as usize][c as usize].status == BlockStatus::FIX {
                                collision = true;
                                break;
                            }
                        }
                    }
                }
                if collision {
                    break;
                }
                ct += 1
            }
        }
        (collision, ct)
    }

    // 更新指定位置的值，如果索引有效就返回 `Some(())`，否则返回 `None`
    fn update_value(&mut self, row: usize, col: usize, value: BlockStatus) -> Option<()> {
        if row < self.grid.len() && col < self.grid[row].len() {
            self.grid[row][col].status = value;
            Some(())
        } else {
            None
        }
    }

    // 获取指定位置的值，如果索引有效则返回 `Some(&i32)`，否则返回 `None`
    fn get_value(&self, row: usize, col: usize) -> Option<&Block> {
        self.grid.get(row)?.get(col)
    }

    fn draw(&self) {
        let score = format!("{}", self.score);
        let lines = format!("{}", self.lines);
        let level = format!("{}", self.level);
        draw_text(11, 12, Color::WHITE, &String::from(score));
        draw_text(12, 12, Color::WHITE, &String::from(level));
        draw_text(13, 12, Color::WHITE, &String::from(lines));

        for row in 0..self.grid.len() {
            for col in 0..self.grid[row].len() {
                if BlockStatus::ACTIVE == self.grid[row][col].status {
                    draw_block(
                        self.x + (row as i32),
                        self.y + (col as i32) * 2,
                        Color::GREEN,
                    );
                } else if BlockStatus::FIX == self.grid[row][col].status {
                    draw_block(
                        self.x + (row as i32),
                        self.y + (col as i32) * 2,
                        self.grid[row][col].color,
                    );
                }
            }
        }

        // 影子
        for row in 0..self.active_teromino.shape.len() {
            for col in 0..self.active_teromino.shape[row].len() {
                if 1 == self.active_teromino.shape[row][col] {
                    draw_text(
                        self.x + self.active_teromino.x + self.offset - 2 + (row as i32),
                        self.y + (self.active_teromino.y + col as i32) * 2,
                        self.active_teromino.color,
                        "░░",
                    );
                }
            }
        }

        // 移动中的 teromino
        for row in 0..self.active_teromino.shape.len() {
            for col in 0..self.active_teromino.shape[row].len() {
                if 1 == self.active_teromino.shape[row][col] {
                    draw_block(
                        self.x + self.active_teromino.x + (row as i32),
                        self.y + (self.active_teromino.y + col as i32) * 2,
                        self.active_teromino.color,
                    );
                } else if 0 == self.active_teromino.shape[row][col] {
                    // draw_block(
                    //     self.x + self.active_teromino.x + (row as i32),
                    //     self.y + (self.active_teromino.y + col as i32) * 2,
                    //     Color::WHITE,
                    // );
                }
            }
        }

        // hold
        for row in 0..self.hold_teromino.shape.len() {
            for col in 0..self.hold_teromino.shape[row].len() {
                if 1 == self.hold_teromino.shape[row][col] {
                    draw_block(
                        6 - (self.hold_teromino.shape.len() as i32 + 1) / 2
                            + self.hold_teromino.x
                            + (row as i32),
                        (self.hold_teromino.y + col as i32 - 2) * 2,
                        self.hold_teromino.color,
                    );
                }
                // else if 0 == self.hold_teromino.shape[row][col] {
                //     draw_block(
                //         4+self.hold_teromino.x + (row as i32),
                //         (self.hold_teromino.y + col as i32 - 2) * 2,
                //         Color::WHITE,
                //     );
                // }
            }
        }

        // next
        for i in 0..self.next_teromino_list.len() {
            for row in 0..self.next_teromino_list[i].shape.len() {
                for col in 0..self.next_teromino_list[i].shape[row].len() {
                    if 1 == self.next_teromino_list[i].shape[row][col] {
                        draw_block(
                            5 + (i as i32) * 5
                                - (self.next_teromino_list[i].shape.len() as i32 + 1) / 2
                                + self.next_teromino_list[i].x
                                + (row as i32),
                            55 + (self.next_teromino_list[i].y + col as i32 - 2) * 2,
                            self.next_teromino_list[i].color,
                        );
                    }
                }
            }
        }
    }
}

fn draw_block(x: i32, y: i32, color: Color) {
    cursor_move(WIN_POS_X + x, WIN_POS_Y + y);
    set_background_color(color);
    print!("  ");
    reset_color();
}

fn draw_text(x: i32, y: i32, color: Color, content: &str) {
    cursor_move(WIN_POS_X + x, WIN_POS_Y + y);
    set_front_color(color);
    print!("{}", content);
    reset_color();
}

fn clear_screen() {
    print!("\x1B[2J");
}

fn cursor_move(row: i32, col: i32) {
    print!("\x1B[{};{}H", WIN_POS_X + row, WIN_POS_Y + col);
}

fn set_front_color(color: Color) {
    print!("\x1B[38;5;{}m", color.to_str());
}

fn set_background_color(color: Color) {
    print!("\x1B[48;5;{}m", color.to_str());
}

fn reset_color() {
    println!("\x1B[0m");
}

fn cursor_visible(visible: bool) {
    if visible {
        print!("\x1B[?25h");
    } else {
        print!("\x1B[?25l");
    }
}

fn current_timestamp() -> u64 {
    match SystemTime::now().duration_since(UNIX_EPOCH) {
        Ok(n) => n.as_secs(),
        Err(_) => panic!("SystemTime before UNIX EPOCH!"),
    }
}

fn init() {
    cursor_visible(false);
    // 启用原始模式以允许非阻塞读取
    terminal::enable_raw_mode().unwrap();
}

fn main_loop() {
    let mut fps_counter = FPSCounter::new();
    let mut cmd = String::from("");

    let mut gard = TetrisGard::new(3, 23, 24, 16);
    gard.reset();

    for _i in 5..1500 {
        fps_counter.tick();

        let input = read_input().unwrap();

        let _a = draw_background_map();

        match input {
            GmAction::QUIT => {
                break;
            }
            GmAction::LEFT => {
                cmd = String::from("L");
            }
            GmAction::RIGHT => {
                cmd = String::from("R");
            }
            GmAction::UP => cmd = String::from("U"),
            GmAction::DOWN => cmd = String::from("D"),
            GmAction::MENU => cmd = String::from("M"),
            GmAction::HELP => cmd = String::from("H"),
            _ => {}
        }

        if cmd == "M" {
            continue;
        }

        draw_text(17, 10, Color::WHITE, &cmd);
        let fps = format!("{}", fps_counter.get_fps());
        draw_text(16, 10, Color::WHITE, &String::from(fps));

        gard.update(input);

        gard.draw();

        thread::sleep(Duration::from_millis(
            220 as u64 - (gard.speed() * 10) as u64,
        ));
    }
}

fn exit() {
    cursor_visible(true);
    cursor_move(0, 0);
    clear_screen();
    // 在退出程序前禁用原始模式
    terminal::disable_raw_mode().unwrap();
    match Command::new("reset").status() {
        Ok(status) if status.success() => {
            println!("Terminal has been reset.");
        }
        Ok(_) => {
            eprintln!("Command executed, but returned a non-zero status.");
        }
        Err(e) => {
            eprintln!("Failed to execute command: {}", e);
        }
    }
}

fn draw_background_map() -> io::Result<()> {
    cursor_move(1, WIN_POS_Y);
    clear_screen();

    let path = Path::new("./teris.map");
    let file = File::open(&path)?;
    let reader = io::BufReader::new(file);

    for line_result in reader.lines() {
        let line = line_result?; // 处理可能出现的错误
        print!("{}\r\n", line);
    }

    Ok(())
}

fn read_input() -> Result<GmAction, std::io::Error> {
    // 非阻塞检查键盘事件
    if event::poll(Duration::from_millis(10))? {
        // 如果有事件，则获取事件
        if let Event::Key(key_event) = event::read()? {
            match key_event.code {
                KeyCode::Char('q') => {
                    return Ok(GmAction::QUIT);
                }
                KeyCode::Char('m') => {
                    return Ok(GmAction::MENU);
                }
                KeyCode::Char('h') => {
                    return Ok(GmAction::HELP);
                }
                KeyCode::Up => {
                    return Ok(GmAction::UP);
                }
                KeyCode::Down => {
                    return Ok(GmAction::DOWN);
                }
                KeyCode::Left => {
                    return Ok(GmAction::LEFT);
                }
                KeyCode::Right => {
                    return Ok(GmAction::RIGHT);
                }
                _ => return Ok(GmAction::UNKNOW),
            }
        }
    }

    return Ok(GmAction::UNKNOW);
}

fn main() {
    init();
    main_loop();
    exit();
    // let shape = vec![vec![0, 1, 1], vec![0, 1, 0], vec![0, 0, 0]];
    // let mut bound_left = shape[0].len() - 1;
    //     for row in 0..shape[0].len() {
    //         for col in 0..shape[row].len() {
    //             if 1 == shape[row][col] {
    //                 bound_left = col;
    //                 break;
    //             }
    //         }
    //     }
    // println!("{}",bound_left);
}
